package com.credithc.customers.api.service.impl;

import com.credithc.baseserv.core.exception.BsException;
import com.credithc.baseserv.core.message.MessageFactory;
import com.credithc.baseserv.core.utils.UUIDUtils;
import com.credithc.customers.api.service.IPreCustomerService;
import com.credithc.customers.base.codes.CustomerCodes;
import com.credithc.customers.base.constants.CustomerConstants;
import com.credithc.customers.base.exception.CustomerException;
import com.credithc.customers.base.mapper.CustomerExtendMapper;
import com.credithc.customers.base.mapper.CustomerIdInfoMapper;
import com.credithc.customers.base.mapper.PreCustomerMapper;
import com.credithc.customers.base.po.CustomerExtendPo;
import com.credithc.customers.base.po.CustomerIdInfoPo;
import com.credithc.customers.base.po.PreCustomerInfoPo;
import com.credithc.customers.base.ro.*;
import com.credithc.customers.base.service.IBasePreCustomerService;
import com.credithc.customers.base.service.ICommonService;
import com.credithc.customers.base.utils.ClassUtils;
import com.credithc.eagleeye.plugins.thread.EagleEyeRunnable;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;

/**
 * @author zhukai
 * @date 2018/11/28 16:43
 */
@Service
@Slf4j
public class PreCustomerServiceImpl implements IPreCustomerService {

    private final PreCustomerMapper preCustomerMapper;

    private final CustomerExtendMapper customerExtendMapper;

    private final ICommonService commService;

    private final IBasePreCustomerService basePreCustomerService;

    private final CustomerIdInfoMapper idInfoMapper;

    private MessageFactory messageFactory;

    @Autowired
    public PreCustomerServiceImpl(PreCustomerMapper preCustomerMapper, CustomerExtendMapper customerExtendMapper, ICommonService commService, IBasePreCustomerService basePreCustomerService, CustomerIdInfoMapper idInfoMapper, MessageFactory messageFactory) {
        this.preCustomerMapper = preCustomerMapper;
        this.customerExtendMapper = customerExtendMapper;
        this.commService = commService;
        this.basePreCustomerService = basePreCustomerService;
        this.idInfoMapper = idInfoMapper;
        this.messageFactory = messageFactory;
    }

    @Override
    public Map<String, String> createPreCustomerNo(BaseRequest<PreCustomerRo> request) {
        return basePreCustomerService.createPreCustomerNo(request);
    }

    @Override
    public List<Map<String, String>> batchCreateCustomerNo(BaseBatchRequest<BatchPreCustomerRo> request) {
        List<Map<String, String>> resList = new ArrayList<>();
        String systemSign = request.getSystemSign();
        String subSystemSign = request.getSubSystemSign();
        String signature = request.getSignature();
        Long requestTimestamp = request.getRequestTimestamp();
        List<BatchPreCustomerRo> ros = request.getBody();
        if (ros.size() > 1000) {
            log.info("============批量条数超过1000条============");
            throw new CustomerException(CustomerCodes.BIZ_VALIDATE_ERROR, "一次批量不允许超过1000条");
        }
        startThread(ros, resList, systemSign, subSystemSign, signature, requestTimestamp);
        log.info("==========线程结束了==========");
        return resList;
    }

    private static int threadNumber = 10;

    private void startThread(List<BatchPreCustomerRo> ros, List<Map<String, String>> resList,
                             String systemSign, String subSystemSign,
                             String signature, Long requestTimestamp) {
        try {
            int roSize = ros.size();
            if (threadNumber > roSize) {
                threadNumber = roSize;
            }
            int avgNum = roSize / threadNumber;
            int remainderNum = roSize % threadNumber;
            int end = 0;
            final CountDownLatch countDownLatch = new CountDownLatch(threadNumber);
            for (int i = 0; i < threadNumber; i++) {
                int start = end;
                end = start + avgNum;
                if (i == (threadNumber - 1)) {
                    end = roSize;
                } else if (i < remainderNum) {
                    end = end + 1;
                }
                String threadName = "线程preCustomer[" + (i + 1) + "]";
                /*BThread bThread = new BThread(ros, start, end, countDownLatch, resList, systemSign, subSystemSign, signature, requestTimestamp);
                bThread.setName(threadName);
                bThread.start();*/
                RunThread runThread = new RunThread(ros, start, end, countDownLatch, resList, systemSign, subSystemSign, signature, requestTimestamp);
                Thread thread = new Thread(new EagleEyeRunnable(runThread));
                thread.setName(threadName);
                thread.start();

            }
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    class BThread extends Thread {
        private List<BatchPreCustomerRo> list;
        private int startIndex;
        private int endIndex;
        private CountDownLatch countDownLatch;
        private List<Map<String, String>> resList;
        private String systemSign;
        private String subSystemSign;
        private String signature;
        private Long requestTimestamp;

        BThread(List<BatchPreCustomerRo> ros, int startIndex, int endIndex,
                CountDownLatch countDownLatch, List<Map<String, String>> resList,
                String systemSign, String subSystemSign,
                String signature, Long requestTimestamp) {
            this.list = ros;
            this.startIndex = startIndex;
            this.endIndex = endIndex;
            this.countDownLatch = countDownLatch;
            this.resList = resList;
            this.systemSign = systemSign;
            this.subSystemSign = subSystemSign;
            this.signature = signature;
            this.requestTimestamp = requestTimestamp;
        }

        @Override
        public void run() {
            List<BatchPreCustomerRo> subList = list.subList(startIndex, endIndex);
            //TODO 逻辑处理
            for (BatchPreCustomerRo ro : subList) {
                Map<String, String> resMap = new HashMap<>(8);
                String dataId = ro.getDataId();
                if (StringUtils.isBlank(dataId)) {
                    resMap.put("dataId", null);
                    resMap.put("errMsg", "dataId不能为空");
                    resList.add(resMap);
                } else {
                    BaseRequest<PreCustomerRo> singleRequest = new BaseRequest<>();
                    singleRequest.setSystemSign(systemSign);
                    singleRequest.setSubSystemSign(subSystemSign);
                    singleRequest.setRequestTimestamp(requestTimestamp);
                    singleRequest.setSignature(signature);
                    singleRequest.setBody(ro);
                    try {
                        Map<String, String> singleResMap;
                        singleResMap = basePreCustomerService.createPreCustomerNo(singleRequest);
                        resMap.put("dataId", dataId);
                        resMap.put("preCustomerNo", singleResMap.get("preCustomerNo"));
                    } catch (BsException e) {
                        String msg = StringUtils.isNotBlank(e.getMsg()) ? e.getMsg() : messageFactory.getInstance(e.getCode()).getMsg();
                        resMap.put("dataId", dataId);
                        resMap.put("errMsg", msg);
                    } catch (Exception e) {
                        resMap.put("dataId", dataId);
                        resMap.put("errMsg", e.getMessage());
                    } finally {
                        resList.add(resMap);
                    }
                }
            }
            countDownLatch.countDown();
        }
    }


    class RunThread implements Runnable {
        private List<BatchPreCustomerRo> list;
        private int startIndex;
        private int endIndex;
        private CountDownLatch countDownLatch;
        private List<Map<String, String>> resList;
        private String systemSign;
        private String subSystemSign;
        private String signature;
        private Long requestTimestamp;

        RunThread(List<BatchPreCustomerRo> ros, int startIndex, int endIndex,
                  CountDownLatch countDownLatch, List<Map<String, String>> resList,
                  String systemSign, String subSystemSign,
                  String signature, Long requestTimestamp) {
            this.list = ros;
            this.startIndex = startIndex;
            this.endIndex = endIndex;
            this.countDownLatch = countDownLatch;
            this.resList = resList;
            this.systemSign = systemSign;
            this.subSystemSign = subSystemSign;
            this.signature = signature;
            this.requestTimestamp = requestTimestamp;
        }

        @Override
        public void run() {
            List<BatchPreCustomerRo> subList = list.subList(startIndex, endIndex);
            //TODO 逻辑处理
            for (BatchPreCustomerRo ro : subList) {
                Map<String, String> resMap = new HashMap<>(8);
                String dataId = ro.getDataId();
                if (StringUtils.isBlank(dataId)) {
                    resMap.put("dataId", null);
                    resMap.put("errMsg", "dataId不能为空");
                    resList.add(resMap);
                } else {
                    BaseRequest<PreCustomerRo> singleRequest = new BaseRequest<>();
                    singleRequest.setSystemSign(systemSign);
                    singleRequest.setSubSystemSign(subSystemSign);
                    singleRequest.setRequestTimestamp(requestTimestamp);
                    singleRequest.setSignature(signature);
                    singleRequest.setBody(ro);
                    try {
                        Map<String, String> singleResMap;
                        singleResMap = basePreCustomerService.createPreCustomerNo(singleRequest);
                        resMap.put("dataId", dataId);
                        resMap.put("preCustomerNo", singleResMap.get("preCustomerNo"));
                    } catch (BsException e) {
                        String msg = StringUtils.isNotBlank(e.getMsg()) ? e.getMsg() : messageFactory.getInstance(e.getCode()).getMsg();
                        resMap.put("dataId", dataId);
                        resMap.put("errMsg", msg);
                    } catch (Exception e) {
                        resMap.put("dataId", dataId);
                        resMap.put("errMsg", e.getMessage());
                    } finally {
                        resList.add(resMap);
                    }
                }
            }
            countDownLatch.countDown();
        }
    }


    @Override
    public Map<String, String> updatePreCustomerNo(BaseRequest<CustomerContactModifyRo> request, String preCustomerNo) {
        String systemSign = request.getSystemSign();
        String subSystemSign = request.getSubSystemSign();
        String contactType = request.getBody().getContactType();
        String contactInfo = request.getBody().getContactInfo();

        //是否有别的系统在用这个用户号
        int existExtendCount = existExtendCount(request, preCustomerNo);
        String newPreCustomerNo = null;
        if (existExtendCount > 0) {
            //有别的系统正在用要修改联系方式的用户号
            PreCustomerInfoPo existPreCustomer = commService.getExistPreCustomer(contactType, contactInfo);

            //新的联系方式有没有系统在用
            if (existPreCustomer == null) {
                //没有别的系统在用新的联系方式
                newPreCustomerNo = ((PreCustomerServiceImpl) AopContext.currentProxy()).createNewPreCustomerNo4Update(request, preCustomerNo);
            } else {
                newPreCustomerNo = existPreCustomer.getPreCustomerNo();
                ((PreCustomerServiceImpl) AopContext.currentProxy()).insertNewExtend4Update(preCustomerNo, systemSign, subSystemSign, newPreCustomerNo);
            }
        } else {
            //没有别的系统正在用这个用户号,要修改信息的用户号就是自己的

            //新的联系方式有没有系统在用
            PreCustomerInfoPo existPreCustomer4newContact = commService.getExistPreCustomer(contactType, contactInfo);
            if (existPreCustomer4newContact != null) {
                //是否有别的系统在用新的联系方式对应的与客户号
                int i = existExtendCount(request, existPreCustomer4newContact.getPreCustomerNo());
                newPreCustomerNo = existPreCustomer4newContact.getPreCustomerNo();
                if (i == 0) {
                    //如果只是本系统，
                    deleteAllOldPreCustomerInfo(preCustomerNo, systemSign, subSystemSign, false, newPreCustomerNo);
                } else {
                    //如果有别的系统在用
                    deleteAllOldPreCustomerInfo(preCustomerNo, systemSign, subSystemSign, true, newPreCustomerNo);
                }
            } else {
                //没有，直接改
                PreCustomerInfoPo po = commService.getExistPreCustomer(preCustomerNo);
                po.setContactType(contactType);
                po.setContactInfo(contactInfo);
                try {
                    preCustomerMapper.updateByPrimaryKeySelective(po);
                } catch (DataAccessException e) {
                    log.info("修改用户的时候更新报错:" + ClassUtils.getClassName() + "--" + ClassUtils.getMethodName() + "--" + e.getMessage());
                    throw new CustomerException(CustomerCodes.DATABASE_ERROR_UPDATE);
                }
                newPreCustomerNo = po.getPreCustomerNo();
            }
        }
        Map<String, String> map = new HashMap<>(3);
        map.put("customerNo", newPreCustomerNo);
        map.put("contactType", contactType);
        map.put("contactInfo", contactInfo);
        return map;
    }

    private int existExtendCount(BaseRequest<CustomerContactModifyRo> request, String preCustomerNo) {
        try {
            String systemSign = request.getSystemSign();
            String subSystemSign = request.getSubSystemSign();
            Example example = new Example(CustomerExtendPo.class);
            example.setDistinct(false);
            Example.Criteria criteria = example.createCriteria();
            criteria.andEqualTo("preCustomerNo", preCustomerNo);
            criteria.andNotEqualTo("systemSign", systemSign);
            if (StringUtils.isNotBlank(subSystemSign)) {
                criteria.andNotEqualTo("subSystemSign", subSystemSign);
            }
            return customerExtendMapper.selectCountByExample(example);
        } catch (DataAccessException e) {
            log.info("查询cust_extend报错:" + ClassUtils.getClassName() + "--" + ClassUtils.getMethodName() + "--" + e.getMessage());
            throw new CustomerException(CustomerCodes.DATABASE_ERROR_QUERY);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void insertNewExtend4Update(String oldPreCustomerNo, String systemSign, String subSystemSign, String newPreCustomerNo) {
        deleteCustomerExtend(oldPreCustomerNo, systemSign, subSystemSign);
        //id 新的有就删掉 没有就带过去
        CustomerIdInfoPo idInfoPo = new CustomerIdInfoPo();
        idInfoPo.setCustomerNo(newPreCustomerNo);
        List<CustomerIdInfoPo> list = idInfoMapper.select(idInfoPo);

        CustomerIdInfoPo oldIdInfoPo = new CustomerIdInfoPo();
        oldIdInfoPo.setCustomerNo(oldPreCustomerNo);
        List<CustomerIdInfoPo> idInfoList = idInfoMapper.select(oldIdInfoPo);
        //todo
        if (list.size() > 0) {
            for (CustomerIdInfoPo po : idInfoList) {
                String sub = po.getSubSystemSign();
                if (sub.contains(subSystemSign)) {
                    String[] subArr = sub.split(",");
                    if (subArr.length == 1) {
                        idInfoMapper.deleteByPrimaryKey(po);
                    } else {
                        StringBuilder sb = new StringBuilder();
                        for (String s : subArr) {
                            if (!s.equals(subSystemSign)) {
                                sb.append(s).append(",");
                            }
                        }
                        po.setSubSystemSign(sb.substring(0, sb.length() - 1).toString());
                        po.setUpdateTime(new Timestamp(System.currentTimeMillis()));
                        idInfoMapper.updateByPrimaryKey(po);
                    }
                }
            }
        } else {

            CustomerIdInfoPo newIdInfoPo = new CustomerIdInfoPo();

            for (CustomerIdInfoPo po : idInfoList) {
                String sub = po.getSubSystemSign();
                if (sub.contains(subSystemSign)) {
                    String[] subArr = sub.split(",");
                    BeanUtils.copyProperties(po, newIdInfoPo);
                    newIdInfoPo.setCreateTime(null);
                    newIdInfoPo.setId(UUIDUtils.getUUID());
                    newIdInfoPo.setCustomerNo(newPreCustomerNo);
                    if (subArr.length == 1) {
                        idInfoMapper.deleteByPrimaryKey(po);
                    } else {
                        StringBuilder sb = new StringBuilder();
                        for (String s : subArr) {
                            if (!s.equals(subSystemSign)) {
                                sb.append(s).append(",");
                            }
                        }
                        po.setSubSystemSign(sb.substring(0, sb.length() - 1).toString());
                        po.setUpdateTime(new Timestamp(System.currentTimeMillis()));
                        idInfoMapper.updateByPrimaryKey(po);
                        newIdInfoPo.setSubSystemSign(subSystemSign);
                    }
                }
            }
            newIdInfoPo.setCreateTime(new Timestamp(System.currentTimeMillis()));
            idInfoMapper.insert(newIdInfoPo);
        }
        commService.updateRelation(systemSign, subSystemSign, oldPreCustomerNo, newPreCustomerNo);
        commService.updateCustomerProduct(systemSign, subSystemSign, oldPreCustomerNo, newPreCustomerNo);
        basePreCustomerService.insertCustomerExtend(systemSign, subSystemSign, null, newPreCustomerNo);
    }

    @Transactional(rollbackFor = Exception.class)
    public String createNewPreCustomerNo4Update(BaseRequest<CustomerContactModifyRo> request, String preCustomerNo) {
        String systemSign = request.getSystemSign();
        String subSystemSign = request.getSubSystemSign();
        String contactType = request.getBody().getContactType();
        String contactInfo = request.getBody().getContactInfo();
        BaseRequest<PreCustomerRo> newRequest = new BaseRequest<>();
        if (newRequest.getBody() == null) {
            newRequest.setBody(new PreCustomerRo());
        }
        newRequest.setSystemSign(systemSign);
        newRequest.setSubSystemSign(subSystemSign);
        newRequest.getBody().setRequestNo(request.getBody().getRequestNo());
        newRequest.getBody().setContactType(contactType);
        newRequest.getBody().setContactInfo(contactInfo);
        newRequest.getBody().setContactVerified(request.getBody().getContactVerified());

        CustomerIdInfoPo idInfoPo = new CustomerIdInfoPo();
        idInfoPo.setCustomerNo(preCustomerNo);
        List<CustomerIdInfoPo> idInfoList = idInfoMapper.select(idInfoPo);
        String customerName = null;
        String idCardType = null;
        String idCardNo = null;
        //todo
        for (CustomerIdInfoPo po : idInfoList) {
            String sub = po.getSubSystemSign();
            if (sub.contains(subSystemSign)) {
                customerName = po.getCustomerName();
                idCardType = po.getIdCardType();
                idCardNo = po.getIdCardNo();
                String[] subArr = sub.split(",");
                if (subArr.length == 1) {
                    idInfoMapper.deleteByPrimaryKey(po);
                } else {
                    StringBuilder sb = new StringBuilder();
                    for (String s : subArr) {
                        if (!s.equals(subSystemSign)) {
                            sb.append(s).append(",");
                        }
                    }
                    po.setSubSystemSign(sb.substring(0, sb.length() - 1).toString());
                    po.setUpdateTime(new Timestamp(System.currentTimeMillis()));
                    idInfoMapper.updateByPrimaryKey(po);
                }
            }
        }
        newRequest.getBody().setCustomerName(customerName);
        newRequest.getBody().setIdCardType(idCardType);
        newRequest.getBody().setIdCardNo(idCardNo);

        String newPreCustomerNo = basePreCustomerService.insertPreCustomer(newRequest, false);
        basePreCustomerService.insertPreCustomerFlow(newRequest, CustomerConstants.STATUS_SUCCESS, null);
        deleteCustomerExtend(preCustomerNo, systemSign, subSystemSign);
        commService.updateRelation(systemSign, subSystemSign, preCustomerNo, newPreCustomerNo);
        commService.updateCustomerProduct(systemSign, subSystemSign, preCustomerNo, newPreCustomerNo);
        return newPreCustomerNo;
    }

    private void deleteCustomerExtend(String preCustomerNo, String systemSign, String subSystemSign) {
        try {
            CustomerExtendPo po = new CustomerExtendPo();
            po.setPreCustomerNo(preCustomerNo);
            po.setSystemSign(systemSign);
            po.setSubSystemSign(subSystemSign);
            customerExtendMapper.delete(po);
        } catch (DataAccessException e) {
            log.info("修改用户的时候删除cust_extend报错:" + ClassUtils.getClassName() + "--" + ClassUtils.getMethodName() + "--" + e.getMessage());
            throw new CustomerException(CustomerCodes.DATABASE_ERROR_DELETE);
        }
    }

    private void deletePreCustomer(String preCustomerNo) {
        try {
            PreCustomerInfoPo po = new PreCustomerInfoPo();
            po.setPreCustomerNo(preCustomerNo);
            preCustomerMapper.delete(po);
        } catch (DataAccessException e) {
            log.info("修改用户的时候删除cust_pre_info报错:" + ClassUtils.getClassName() + "--" + ClassUtils.getMethodName() + "--" + e.getMessage());
            throw new CustomerException(CustomerCodes.DATABASE_ERROR_DELETE);
        }
    }

    private void deleteCustomerIdInfo(String preCustomerNo) {
        try {
            CustomerIdInfoPo po = new CustomerIdInfoPo();
            po.setCustomerNo(preCustomerNo);
            idInfoMapper.delete(po);
        } catch (DataAccessException e) {
            log.info("修改用户的时候删除cust_id_info报错:" + ClassUtils.getClassName() + "--" + ClassUtils.getMethodName() + "--" + e.getMessage());
            throw new CustomerException(CustomerCodes.DATABASE_ERROR_DELETE);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void deleteAllOldPreCustomerInfo(String oldPreCustomerNo, String systemSign, String subSystemSign, boolean needAddExtend, String newPreCutomerNo) {
        deletePreCustomer(oldPreCustomerNo);
        deleteCustomerIdInfo(oldPreCustomerNo);
        deleteCustomerExtend(oldPreCustomerNo, systemSign, subSystemSign);
        if (needAddExtend) {
            basePreCustomerService.insertCustomerExtend(systemSign, subSystemSign, null, newPreCutomerNo);
        }
        commService.updateRelation(systemSign, subSystemSign, oldPreCustomerNo, newPreCutomerNo);
        commService.updateCustomerProduct(systemSign, subSystemSign, oldPreCustomerNo, newPreCutomerNo);
    }

}
